package com.mnsk.generator.controller;

import com.alibaba.fastjson.JSON;
import com.mnsk.generator.common.utils.text.Convert;
import com.mnsk.generator.domain.SysDataSource;
import com.mnsk.generator.domain.Table;
import com.mnsk.generator.domain.TableColumn;
import com.mnsk.generator.common.constant.Constants;
import com.mnsk.generator.common.core.controller.BaseController;
import com.mnsk.generator.common.core.domain.AjaxResult;
import com.mnsk.generator.common.core.domain.CxSelect;
import com.mnsk.generator.common.core.page.TableDataInfo;
import com.mnsk.generator.common.exception.DemoModeException;
import com.mnsk.generator.common.utils.StringUtils;
import com.mnsk.generator.query.TableQuery;
import com.mnsk.generator.service.SysDataSourceService;
import com.mnsk.generator.service.TableColumnService;
import com.mnsk.generator.service.TableService;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 代码生成操作处理
 *
 * @author admin
 */
@Controller
@RequestMapping("/tool/gen")
public class GenController extends BaseController {

    private static final String PREFIX = "tool/gen";

    @Resource
    private TableService genTableService;
    @Resource
    private SysDataSourceService sysDataSourceService;
    @Resource
    private TableColumnService genTableColumnService;

    /**
     * 代码生成列表界面
     */
    @GetMapping()
    public String gen(ModelMap modelMap) {
        List<SysDataSource> dataSourceList = sysDataSourceService.list();
        modelMap.put("dataSourceList", dataSourceList);
        return PREFIX + "/gen";
    }

    /**
     * 根据业务表id生成预览代码信息并进入界面展示
     */
    @GetMapping("/preview/{tableId}")
    public String preview(@PathVariable("tableId") Long tableId, ModelMap modelMap) {
        modelMap.put("previewCode", genTableService.previewCode(tableId));
        return PREFIX + "/preview";
    }

    /**
     * 根据业务表id生成预览代码对外API
     */
    @ResponseBody
    @GetMapping("/previewCode/{tableId}")
    public AjaxResult<Map<String, String>> previewCode(@PathVariable("tableId") Long tableId) {
        Map<String, String> dataMap = genTableService.previewCode(tableId);
        return AjaxResult.success(dataMap);
    }

    /**
     * 分页条件查询获取业务表结构
     *
     * @param tableQuery 查询参数
     * @return 列表
     */
    @ResponseBody
    @PostMapping("/list")
    public TableDataInfo<Table> genList(TableQuery tableQuery) {
        return toPageResult(genTableService.list(tableQuery.autoPageWrapper()));
    }

    /**
     * 查询数据库列表
     */
    @ResponseBody
    @PostMapping("/db/list")
    public TableDataInfo<Table> dataList(TableQuery tableQuery) {
        startPage();
        List<Table> list = genTableService.selectDbTableList(tableQuery);
        return toPageResult(list);
    }

    /**
     * 查询数据表字段列表
     */
    @ResponseBody
    @PostMapping("/column/list")
    public TableDataInfo<TableColumn> columnList(TableColumn tableColumn) {
        TableDataInfo<TableColumn> dataInfo = new TableDataInfo<>();
        List<TableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(tableColumn.getTableId());
        dataInfo.setRows(list);
        dataInfo.setTotal(list.size());
        return dataInfo;
    }

    /**
     * 导入表结构
     */
    @GetMapping("/importTable/{dataSourceId}")
    public String importTable(@PathVariable("dataSourceId") Long id, ModelMap modelMap) {
        modelMap.put("dataSourceId", id);
        return PREFIX + "/importTable";
    }

    /**
     * 根据表名与数据源批量导入表结构（多个用逗号分隔）
     */
    @ResponseBody
    @PostMapping("/importTable")
    public AjaxResult<Object> importTableSave(String tables, Long dataSourceId) {
        String[] tableNames = Convert.toStrArray(tables);
        // 查询表信息
        List<Table> tableList = genTableService.selectDbTableListByNames(tableNames, dataSourceId);
        genTableService.importGenTable(tableList, dataSourceId);
        return AjaxResult.success();
    }

    /**
     * 修改代码生成业务
     */
    @GetMapping("/edit/{tableId}")
    public String edit(@PathVariable("tableId") Long tableId, ModelMap modelMap) {
        Table table = genTableService.selectGenTableById(tableId);
        List<Table> tables = genTableService.selectGenTableAll(table.getDataSourceId());
        List<CxSelect> cxSelect = new ArrayList<>();
        for (Table genTable : tables) {
            if (!StringUtils.equals(table.getTableName(), genTable.getTableName())) {
                CxSelect cxTable = new CxSelect(genTable.getTableName(), genTable.getTableName() + '：' + genTable.getTableComment());
                List<CxSelect> cxColumns = new ArrayList<>();
                for (TableColumn tableColumn : genTable.getColumns()) {
                    cxColumns.add(new CxSelect(tableColumn.getColumnName(), tableColumn.getColumnName() + '：' + tableColumn.getColumnComment()));
                }
                cxTable.setS(cxColumns);
                cxSelect.add(cxTable);
            }
        }
        modelMap.put("table", table);
        modelMap.put("data", JSON.toJSON(cxSelect));
        return PREFIX + "/edit";
    }

    /**
     * 修改保存代码生成业务
     */
    @ResponseBody
    @PostMapping("/edit")
    public AjaxResult<Object> editSave(@Validated Table table) {
        if (Constants.DEMO_TAG.equals(table.getTableId())) {
            throw new DemoModeException();
        }
        genTableService.validateEdit(table);
        genTableService.updateGenTable(table);
        return AjaxResult.success();
    }

    /**
     * 根据id删除业务表数据（多个用逗号分隔）
     *
     * @param ids ids
     * @return 结果
     */
    @ResponseBody
    @PostMapping("/remove")
    public AjaxResult<Object> remove(String ids) {
        List<Long> list = Arrays.asList(Convert.toLongArray(ids));
        if (list.contains(Constants.DEMO_TAG)) {
            throw new DemoModeException();
        }
        genTableService.deleteGenTableByIds(list);
        return AjaxResult.success();
    }

    /**
     * 生成代码（下载方式）
     */
    @GetMapping("/download/{tableName}")
    public void download(HttpServletResponse response, @PathVariable("tableName") String tableName) throws IOException {
        byte[] data = genTableService.downloadCode(tableName);
        genCode(response, data);
    }

    /**
     * 生成代码（自定义路径）
     */
    @ResponseBody
    @GetMapping("/genCode/{tableName}")
    public AjaxResult<Object> genCode(@PathVariable("tableName") String tableName) {
        genTableService.generatorCode(tableName);
        return AjaxResult.success();
    }

    /**
     * 从数据库同步更新表结构
     */
    @ResponseBody
    @GetMapping("/synchDb/{tableName}/{tableId}")
    public AjaxResult<Object> synchDb(@PathVariable("tableName") String tableName, @PathVariable("tableId") Long tableId) {
        genTableService.syncDb(tableName, tableId);
        return AjaxResult.success();
    }

    /**
     * 批量生成代码
     */
    @ResponseBody
    @GetMapping("/batchGenCode")
    public void batchGenCode(HttpServletResponse response, String tables) throws IOException {
        String[] tableNames = Convert.toStrArray(tables);
        byte[] data = genTableService.downloadCode(tableNames);
        genCode(response, data);
    }

    /**
     * 生成zip文件
     */
    private void genCode(HttpServletResponse response, byte[] data) throws IOException {
        response.reset();
        response.setHeader("Content-Disposition", "attachment; filename=\"code.zip\"");
        response.addHeader("Content-Length", "" + data.length);
        response.setContentType("application/octet-stream; charset=UTF-8");
        IOUtils.write(data, response.getOutputStream());
    }

}
